package vn.edu.saigontech.ncms.web.teacher.report;

import java.text.Collator;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import vn.edu.saigontech.ncms.model.enumeration.Nationality;
import vn.edu.saigontech.ncms.model.enumeration.TeacherType;
import vn.edu.saigontech.ncms.model.info.Offering;
import vn.edu.saigontech.ncms.model.info.Teacher;
import vn.edu.saigontech.ncms.model.teaching.TeachingInterruption;
import vn.edu.saigontech.ncms.service.DayOffService;
import vn.edu.saigontech.ncms.service.OfferingService;
import vn.edu.saigontech.ncms.util.Checker;
import vn.edu.saigontech.ncms.util.DateUtil;

public class TeachingHourReport {

	private LinkedList<Date> range = new LinkedList<Date>();
	private LinkedList<TeacherTeachingDetail> teachings = new LinkedList<TeacherTeachingDetail>();
	private LinkedList<TeacherTeachingDetail> vietnameseTeachings = new LinkedList<TeacherTeachingDetail>();
	private LinkedList<TeacherTeachingDetail> foreignTeachings = new LinkedList<TeacherTeachingDetail>();
	
	private int totalSessions;
	private double totalTeachingHours;
	
	public TeachingHourReport(Date fromDate, Date toDate) {
		this.range = new LinkedList<Date>(DateUtil.sequence(fromDate, toDate));
		this.init();
	}
	
	public void init() {
		Collection<Offering> offerings = OfferingService.INSTANCE.findByDate(this.range.getFirst(), this.range.getLast());
		for(Offering offering : offerings) {
			List<Date> dates = DateUtil.sequenceAsList(offering.getStartDate(), offering.getEndDate());
			
			LinkedList<Date> tmp1 = new LinkedList<Date>();
			tmp1.addAll(range);
			tmp1.retainAll(dates);
			
			LinkedList<Date> tmp2 = new LinkedList<Date>();
			for(Date date : tmp1) {
				if(!DayOffService.INSTANCE.exists(date)) {
					tmp2.add(date);
				}
			}
			
			for(Date date : tmp2) {
				// included switch and interruption (transfers and substitutions)
				Teacher teacher = offering.getTeacher(date);
				TeachingInterruption interruption = offering.getInstructorInterruption(date);
				int status = 0;
				if(Checker.isNotNull(interruption)) {
					status = interruption.getStatus(date);
				}
				if(status != TeachingInterruption.CANCEL_REASON && Checker.isNotNull(teacher)) {
					String fullName = teacher.getFullName();
					TeacherTeachingDetail teacherDetail = this.getTeaching(fullName);
					if(Checker.isNull(teacherDetail)) {
						teacherDetail = new TeacherTeachingDetail(teacher.getId(), teacher.getFirstName(), fullName, TeacherType.INSTRUCTOR, teacher.getNationality());
						this.teachings.add(teacherDetail);
					}
					OfferingTeachingDetail offeringDetail = teacherDetail.getDetail(offering);
					if(Checker.isNull(offeringDetail)) {
						offeringDetail = new OfferingTeachingDetail(offering, offering.getLevel().getHours(), OfferingService.HOURS_PER_SESSION, 1, "");
						teacherDetail.add(offeringDetail);
					} else {
						offeringDetail.setSessions(offeringDetail.getSessions() + 1);
					}
				}
				Teacher ta = offering.getTA(date);
				TeachingInterruption taInterruption = offering.getTAInterruption(date);
				int taStatus = 0;
				if(Checker.isNotNull(taInterruption)) {
					taStatus = taInterruption.getStatus(date);
				}
				if(taStatus != TeachingInterruption.CANCEL_REASON && Checker.isNotNull(ta)) {
					String taFullName = ta.getFullName() + " (Trợ Giảng)";
					TeacherTeachingDetail taDetail = this.getTeaching(taFullName);
					if(Checker.isNull(taDetail)) {
						taDetail = new TeacherTeachingDetail(ta.getId(), ta.getFirstName(), taFullName, TeacherType.TA, ta.getNationality());
						this.teachings.add(taDetail);
					}
					OfferingTeachingDetail taOfferingDetail = taDetail.getDetail(offering);
					if(Checker.isNull(taOfferingDetail)) {
						taOfferingDetail = new OfferingTeachingDetail(offering, offering.getLevel().getHours(), OfferingService.HOURS_PER_SESSION, 1, "");
						taDetail.add(taOfferingDetail);
					} else {
						taOfferingDetail.setSessions(taOfferingDetail.getSessions() + 1);
					}
				}
			}
		}
		this.seperateTeaching();
	}
	
	private TeacherTeachingDetail getTeaching(String teacher) {
		for(TeacherTeachingDetail each : this.teachings) {
			if(each.getTeacher().equalsIgnoreCase(teacher)) {
				return each;
			}
		}
		return null;
	}
	
	private void seperateTeaching() {
		Collections.sort(this.teachings, new Comparator<TeacherTeachingDetail>() {
			@Override
			public int compare(TeacherTeachingDetail o1, TeacherTeachingDetail o2) {
				Locale[] locales = Collator.getAvailableLocales();
				Locale locale = Locale.getDefault();
				for (int i = 0; i < locales.length; i++) {
					if(locales[i].getLanguage().equals("vi")) {
						locale = locales[i];
						continue;
					}
				}
				Collator collator = Collator.getInstance(locale);
				return collator.compare(o1.getSortName(), o2.getSortName());
			}
		});
		for(TeacherTeachingDetail detail : this.teachings) {
			this.totalSessions += detail.getTotalSessions();
			this.totalTeachingHours += detail.getTotalTeachingHours();
			detail.removeInvalidDetails();
			if(detail.getDetails().isEmpty()) continue;
			if(Nationality.VIETNAM.equals(detail.getNationality())) {
				this.vietnameseTeachings.add(detail);
			}
			else {
				this.foreignTeachings.add(detail);
			}
		}
	}
	
	public LinkedList<TeacherTeachingDetail> getVietnameseTeachings() {
		return vietnameseTeachings;
	}

	public LinkedList<TeacherTeachingDetail> getForeignTeachings() {
		return foreignTeachings;
	}

	public int getTotalSessions() {
		return totalSessions;
	}

	public double getTotalTeachingHours() {
		return totalTeachingHours;
	}
}